"""
自动权限生成系统
当添加新的URL功能时，自动生成相应的权限
"""
import importlib
import inspect
import os
from django.urls import get_resolver
from django.conf import settings
from rbac.models import Permission, Role, RolePermission
from functools import wraps


class AutoPermissionGenerator:
    """自动权限生成器 - 简化版"""
    
    def __init__(self):
        # 存储发现的视图函数
        self.discovered_views = {}
        # 存储URL name到视图函数的映射
        self.url_name_mapping = {}
    
    def require_permission(self, permission_code, permission_name=None, group=None, description=None):
        """
        装饰器：标记视图需要权限控制
        
        @require_permission('app.feature.action', '功能名称', '功能分组', '功能描述')
        def my_view(request):
            pass
        """
        def decorator(view_func):
            # 设置默认值
            final_permission_name = permission_name or f"{view_func.__name__}权限"
            final_group = group or "默认分组"
            final_description = description or f"{view_func.__name__}的访问权限"
                
            @wraps(view_func)
            def wrapper(request, *args, **kwargs):
                # 权限检查逻辑
                if hasattr(request, 'current_user') and request.current_user:
                    from rbac.models import RbacUser
                    try:
                        user = RbacUser.objects.get(id=request.current_user['id'])
                        if not user.has_permission(permission_code):
                            from django.contrib import messages
                            from django.shortcuts import redirect
                            from django.urls import reverse
                            messages.error(request, f'您没有权限访问此功能: {final_permission_name}')
                            # 重定向到仪表板或首页
                            try:
                                return redirect(reverse('rbac:dashboard'))
                            except:
                                return redirect('/')
                    except RbacUser.DoesNotExist:
                        from django.shortcuts import redirect
                        try:
                            return redirect(reverse('rbac:login'))
                        except:
                            return redirect('/')
                
                return view_func(request, *args, **kwargs)
            
            # 保留原函数的元数据
            wrapper.__name__ = view_func.__name__
            wrapper.__doc__ = view_func.__doc__
            wrapper.permission_info = {
                'code': permission_code,
                'name': final_permission_name,
                'group': final_group,
                'description': final_description
            }
            
            return wrapper
        return decorator

    def scan_all_apps_views(self):
        """扫描所有Django应用的视图函数"""
        from django.apps import apps
        
        # 获取所有安装的应用（排除Django内置应用）
        installed_apps = [app for app in apps.get_app_configs() 
                         if not app.name.startswith('django.')]
        
        print(f"🔍 扫描中的应用: {[app.name for app in installed_apps]}")
        
        # 扫描URL配置，建立URL name到视图函数的映射
        self._scan_url_configs()
        
        # 扫描各应用的视图函数
        for app_config in installed_apps:
            app_name = app_config.name
            print(f"📦 正在扫描应用: {app_name}")
            
            # 查找应用中的views模块
            views_modules = self._find_views_modules(app_name)
            
            for module_path in views_modules:
                try:
                    module = importlib.import_module(module_path)
                    
                    for name, obj in inspect.getmembers(module, inspect.isfunction):
                        if (not name.startswith('_') and 
                            name not in self._get_excluded_functions()):
                            
                            view_key = f"{module_path}.{name}"
                            self.discovered_views[view_key] = {
                                'function': obj,
                                'name': name,
                                'module': module_path,
                                'app': app_name,
                                'has_permission_info': hasattr(obj, 'permission_info'),
                                'docstring': obj.__doc__ or f"{name}功能"
                            }
                            
                except ImportError as e:
                    print(f"⚠️  无法导入模块 {module_path}: {e}")
                except Exception as e:
                    print(f"⚠️  扫描模块 {module_path} 时出错: {e}")
        
        print(f"🎉 扫描完成，发现 {len(self.discovered_views)} 个视图函数")
        return self.discovered_views
    
    def _scan_url_configs(self):
        """扫描URL配置，建立URL name到视图函数的映射"""
        try:
            # 获取主URL解析器
            resolver = get_resolver()
            # 递归扫描所有URL模式
            self._scan_url_patterns(resolver, '')
        except Exception as e:
            print(f"⚠️  扫描URL配置时出错: {e}")
    
    def _scan_url_patterns(self, resolver, prefix):
        """递归扫描URL模式"""
        for pattern in resolver.url_patterns:
            # 获取完整的URL name
            url_name = None
            if hasattr(pattern, 'name') and pattern.name:
                if prefix:
                    url_name = f"{prefix}:{pattern.name}"
                else:
                    url_name = pattern.name
            
            # 如果有URL name且有callback（视图函数）
            if url_name and hasattr(pattern, 'callback'):
                view_func = pattern.callback
                # 获取视图函数的模块和名称
                if hasattr(view_func, '__module__') and hasattr(view_func, '__name__'):
                    view_key = f"{view_func.__module__}.{view_func.__name__}"
                    self.url_name_mapping[view_key] = url_name
                    print(f"🔗 URL映射: {url_name} -> {view_key}")
            
            # 如果是include的模式，继续递归
            if hasattr(pattern, 'url_patterns'):
                # 获取namespace
                namespace = getattr(pattern, 'namespace', None) or getattr(pattern, 'app_name', None)
                if namespace:
                    new_prefix = f"{prefix}:{namespace}" if prefix else namespace
                else:
                    new_prefix = prefix
                self._scan_url_patterns(pattern, new_prefix)
    
    def _find_views_modules(self, app_name):
        """查找应用中的所有views模块"""
        modules = []
        possible_modules = [f"{app_name}.views", f"{app_name}.view"]
        
        try:
            views_package = f"{app_name}.views"
            views_module = importlib.import_module(views_package)
            
            if hasattr(views_module, '__path__'):
                for file_path in views_module.__path__:
                    if os.path.isdir(file_path):
                        for filename in os.listdir(file_path):
                            if (filename.endswith('.py') and 
                                not filename.startswith('_') and 
                                filename != '__init__.py'):
                                module_name = filename[:-3]
                                possible_modules.append(f"{views_package}.{module_name}")
            else:
                possible_modules.append(views_package)
        except ImportError:
            pass
        
        for module_path in possible_modules:
            try:
                importlib.import_module(module_path)
                modules.append(module_path)
            except ImportError:
                continue
        
        return modules
    
    def _get_excluded_functions(self):
        """获取需要排除的函数名列表"""
        return {
            'has_user_permission', 'save_images', 'get_report_data',
            'csrf_exempt', 'require_http_methods', 'login_required',
            'authenticate', 'login', 'logout', 'redirect', 'render', 'reverse',
            'require_permission'
        }
    
    def generate_permission_from_view(self, view_name, view_info):
        """从视图信息生成权限定义"""
        if view_info.get('has_permission_info'):
            # 如果视图已经有权限信息，使用它
            return view_info['function'].permission_info
        
        # 根据视图名称推断权限类型和分组
        view_func_name = view_info['name']
        module_name = view_info['module']
        
        # 尝试从URL配置中获取name属性作为权限名称
        url_name = None
        view_key = f"{module_name}.{view_func_name}"
        if view_key in self.url_name_mapping:
            url_name = self.url_name_mapping[view_key]
        
        # 确定权限分组
        app_name = view_info.get('app', 'unknown')
        group = self._determine_permission_group(module_name, app_name)
        
        # 生成权限代码
        permission_code = f"{app_name.lower()}.{view_func_name}"
        
        # 使用URL name作为权限名称，如果没有则使用视图函数名
        permission_name = url_name if url_name else view_func_name
        
        # 生成描述
        description = view_info.get('docstring', f"访问{permission_name}的权限")
        if description == f"{view_func_name}功能":
            description = f"允许用户访问{permission_name}功能"
        
        # 返回权限信息字典
        return {
            'code': permission_code,
            'name': permission_name,
            'group': group,
            'description': description
        }
    
    def _determine_permission_group(self, module_name, app_name):
        """确定权限分组"""
        if 'account' in module_name:
            return f'{app_name.upper()}账户管理'
        elif 'auth' in module_name:
            return f'{app_name.upper()}认证管理'
        elif 'management' in module_name or 'manage' in module_name:
            return f'{app_name.upper()}管理功能'
        elif 'demo' in module_name or 'test' in module_name:
            return f'{app_name.upper()}演示功能'
        elif 'config' in module_name or 'setting' in module_name:
            return f'{app_name.upper()}配置管理'
        elif 'template' in module_name:
            return f'{app_name.upper()}模板管理'
        elif app_name.lower() == 'rbac':
            return 'RBAC权限管理'
        else:
            return f'{app_name.upper()}功能模块'
    
    def clean_orphaned_permissions(self):
        """清理孤立权限（对应视图函数已不存在的权限）"""
        from rbac.models import Permission, RolePermission
        
        # 先扫描所有存在的视图函数
        self.scan_all_apps_views()
        
        # 获取所有存在的权限代码
        discovered_permission_codes = set()
        for view_name, view_info in self.discovered_views.items():
            perm_info = self.generate_permission_from_view(view_name, view_info)
            discovered_permission_codes.add(perm_info['code'])
        
        # 获取数据库中所有的权限
        all_permissions = Permission.objects.all()
        orphaned_permissions = []
        
        for permission in all_permissions:
            # 检查权限代码是否在发现的视图中
            if permission.code not in discovered_permission_codes:
                # 这是一个孤立权限
                orphaned_permissions.append(permission)
                print(f"🗑️  发现孤立权限: {permission.name} ({permission.code})")
        
        if not orphaned_permissions:
            print("🎉 没有发现孤立权限")
            return {'deleted': [], 'count': 0}
        
        # 删除孤立权限
        print(f"\n⚠️  发现 {len(orphaned_permissions)} 个孤立权限，即将删除...")
        
        deleted_permissions = []
        for permission in orphaned_permissions:
            try:
                # 先删除角色权限关联
                RolePermission.objects.filter(permission=permission).delete()
                # 再删除权限本身
                permission_name = permission.name
                permission_code = permission.code
                permission.delete()
                deleted_permissions.append({
                    'name': permission_name,
                    'code': permission_code
                })
                print(f"✅ 已删除孤立权限: {permission_name} ({permission_code})")
            except Exception as e:
                print(f"❌ 删除权限 {permission.code} 失败: {str(e)}")
        
        print(f"\n🎉 清理完成，共删除 {len(deleted_permissions)} 个孤立权限")
        
        return {
            'deleted': deleted_permissions,
            'count': len(deleted_permissions)
        }
    
    def auto_create_permissions(self, scan_all_apps=True, clean_orphaned=False):
        """自动创建发现的权限并可选清理孤立权限"""
        # 如果需要清理孤立权限，先执行清理
        deleted_result = {'deleted': [], 'count': 0}
        if clean_orphaned:
            deleted_result = self.clean_orphaned_permissions()
        
        # 扫描视图函数
        if not self.discovered_views:
            if scan_all_apps:
                self.scan_all_apps_views()
            else:
                self.scan_all_apps_views()
        
        created_permissions = []
        updated_permissions = []
        
        # 为每个发现的视图函数生成权限
        for view_name, view_info in self.discovered_views.items():
            perm_info = self.generate_permission_from_view(view_name, view_info)
            
            permission, created = Permission.objects.get_or_create(
                code=perm_info['code'],
                defaults={
                    'name': perm_info['name'],
                    'group': perm_info['group'],
                    'description': perm_info['description']
                }
            )
            
            if created:
                created_permissions.append(permission)
                print(f"✅ 创建权限: {permission.name} ({permission.code})")
            else:
                # 更新现有权限的信息
                updated = False
                if permission.name != perm_info['name']:
                    permission.name = perm_info['name']
                    updated = True
                if permission.description != perm_info['description']:
                    permission.description = perm_info['description']
                    updated = True
                
                if updated:
                    permission.save()
                    updated_permissions.append(permission)
                    print(f"🔄 更新权限: {permission.name} ({permission.code})")
                else:
                    print(f"⏸️  权限已存在: {permission.name} ({permission.code})")
        
        return {
            'created': created_permissions,
            'updated': updated_permissions,
            'deleted': deleted_result['deleted'],
            'total_discovered': len(self.discovered_views),
            'deleted_count': deleted_result['count']
        }
    
    def assign_permissions_to_default_roles(self, created_permissions):
        """将新创建的权限分配给默认角色"""
        if not created_permissions:
            return
        
        # 角色权限分配规则
        role_rules = {
            'super_admin': 'all',  # 超级管理员获得所有权限
            'admin': {  # 管理员获得管理类权限
                'include_groups': ['*功能模块', '*账户管理', '*配置管理', '*模板管理', 'RBAC权限管理'],
                'exclude_codes': []
            },
            'user': {  # 普通用户获得基础功能权限
                'include_groups': ['*功能模块', '*账户管理'],
                'exclude_keywords': ['all_', 'delete', 'edit_config', 'admin', 'manage']
            }
        }
        
        for role_code, rule in role_rules.items():
            try:
                role = Role.objects.get(code=role_code, is_active=True)
                
                for permission in created_permissions:
                    should_assign = False
                    
                    if rule == 'all':
                        should_assign = True
                    elif isinstance(rule, dict):
                        # 基于分组和关键词的智能分配
                        include_groups = rule.get('include_groups', [])
                        exclude_codes = rule.get('exclude_codes', [])
                        exclude_keywords = rule.get('exclude_keywords', [])
                        
                        # 检查是否匹配包含的分组
                        group_matched = False
                        for group_pattern in include_groups:
                            if group_pattern == permission.group:
                                group_matched = True
                                break
                            elif group_pattern.endswith('*') and permission.group.endswith(group_pattern[:-1]):
                                group_matched = True
                                break
                            elif group_pattern.startswith('*') and permission.group.endswith(group_pattern[1:]):
                                group_matched = True
                                break
                        
                        if group_matched:
                            # 检查是否在排除列表中
                            if permission.code not in exclude_codes:
                                # 检查是否包含排除关键词
                                has_exclude_keyword = any(keyword in permission.code for keyword in exclude_keywords)
                                if not has_exclude_keyword:
                                    should_assign = True
                    
                    if should_assign:
                        role_perm, created = RolePermission.objects.get_or_create(
                            role=role,
                            permission=permission
                        )
                        if created:
                            print(f"🎯 为角色 {role.name} 分配权限: {permission.name}")
                            
            except Role.DoesNotExist:
                print(f"⚠️  角色 {role_code} 不存在，跳过权限分配")
    
    def get_permission_status_report(self):
        """获取权限状态报告"""
        if not self.discovered_views:
            self.scan_all_apps_views()
        
        # 统计信息
        total_views = len(self.discovered_views)
        views_with_permissions = sum(1 for v in self.discovered_views.values() if v['has_permission_info'])
        
        # 按模块分组
        by_module = {}
        for view_name, view_info in self.discovered_views.items():
            module = view_info['module']
            if module not in by_module:
                by_module[module] = []
            by_module[module].append({
                'name': view_name,
                'has_permission': view_info['has_permission_info']
            })
        
        return {
            'total_views': total_views,
            'views_with_permissions': views_with_permissions,
            'views_without_permissions': total_views - views_with_permissions,
            'by_module': by_module,
            'discovered_views': self.discovered_views
        }


# 全局实例
auto_permission_generator = AutoPermissionGenerator()

# 便捷装饰器
require_permission = auto_permission_generator.require_permission

def sync_permissions(scan_all_apps=True):
    """同步权限 - 扫描并创建所有发现的权限"""
    if scan_all_apps:
        print("🔍 开始扫描所有应用的视图函数...")
    else:
        print("🔍 开始扫描项目的视图函数...")
    
    result = auto_permission_generator.auto_create_permissions(scan_all_apps=scan_all_apps)
    
    print(f"\n📊 扫描完成:")
    print(f"   - 发现视图: {result['total_discovered']} 个")
    print(f"   - 新创建权限: {len(result['created'])} 个")
    print(f"   - 更新权限: {len(result['updated'])} 个")
    
    # 为新权限分配角色
    if result['created']:
        print(f"\n🎯 为默认角色分配新权限...")
        auto_permission_generator.assign_permissions_to_default_roles(result['created'])
    
    return result

def get_permission_report():
    """获取权限状态报告"""
    return auto_permission_generator.get_permission_status_report()